<!DOCTYPE html>
<html>

<head>
  <title>Unit Tests</title>
  <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.16.0.css">
</head>

<body>
  <div id="qunit"></div>
  <div id="qunit-fixture"></div>

  <script src="https://code.jquery.com/qunit/qunit-2.16.0.js"></script>
  <script src="/static/ast.js"></script>
  <script src="/static/matrix.js"></script>
  <script>
    function new_Node(a, b) {
      if (b === undefined) return a;
      else return new Node(a, b);
    }

    QUnit.test("multiplyMatrices: multiplication of matrices", function (assert) {
      // Test case 1: 2x2 matrix multiplication
      var matrixA = [[1, 2], [3, 4]];
      var matrixB = [[5, 6], [7, 8]];
      var expected = [[19, 22], [43, 50]];
      assert.deepEqual(multiplyMatrices(matrixA, matrixB), expected, "Multiplication of 2x2 matrices");

      // Test case 2: 3x2 matrix multiplied by 2x3 matrix
      matrixA = [[1, 2], [3, 4], [5, 6]];
      matrixB = [[7, 8, 9], [10, 11, 12]];
      expected = [[27, 30, 33], [61, 68, 75], [95, 106, 117]];
      assert.deepEqual(multiplyMatrices(matrixA, matrixB), expected, "Multiplication of 3x2 and 2x3 matrices");
    });

    QUnit.test("matrixPower: calculation of matrix power", function (assert) {
      // Test case 1: 2x2 matrix raised to power 2
      var matrix = [[1, 2], [3, 4]];
      var power = 2;
      var expected = [[7, 10], [15, 22]];
      assert.deepEqual(matrixPower(matrix, power), expected, "Matrix power calculation");

      // Test case 2: 3x3 matrix raised to power 3
      matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
      power = 3;
      expected = [[468, 576, 684], [1062, 1305, 1548], [1656, 2034, 2412]];
      assert.deepEqual(matrixPower(matrix, power), expected, "Matrix power calculation");
    });

    QUnit.test("evaluateExpression: evaluation of expressions", function (assert) {
      var env = {
        A: [[1, 2], [3, 4]],
        B: [[5, 6], [7, 8]],
        C: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
      };

      // Test case 1: Evaluate expression "A * B"
      var ast = new_Node("multiply", [new_Node("A"), new_Node("B")]);
      var expected = [[19, 22], [43, 50]];
      assert.deepEqual(evaluateExpression(ast, env), expected, "Evaluation of matrix multiplication");

      // Test case 2: Evaluate expression "C ^ 3"
      ast = new_Node("power", [new_Node("C"), new_Node(3)]);
      expected = [[468, 576, 684], [1062, 1305, 1548], [1656, 2034, 2412]];
      assert.deepEqual(evaluateExpression(ast, env), expected, "Evaluation of matrix power");

      // Test case 3: Evaluate expression "D"
      ast = new_Node("D");
      assert.throws(function () {
        evaluateExpression(ast, env);
      }, /Variable "D" is not defined in the environment/, "Evaluation of undefined variable");
    });

    QUnit.test('inverseMatrix', function (assert) {
      // Test Case 1
      const matrix1 = [
        [1, 2],
        [3, 4]
      ];
      const expectedInverse1 = [
        [-2, 1],
        [1.5, -0.5]
      ];
      assert.deepEqual(inverseMatrix(matrix1), expectedInverse1, 'Inverse calculated correctly.');

      // Test Case 2
      const matrix2 = [
        [1, 0, 0],
        [0, 2, 0],
        [0, 0, 3]
      ];
      const expectedInverse2 = [
        [1, 0, 0],
        [0, 0.5, 0],
        [0, 0, 1 / 3]
      ];
      assert.deepEqual(inverseMatrix(matrix2), expectedInverse2, 'Inverse calculated correctly.');

      // Test Case 3: Non-square matrix
      const matrix3 = [
        [1, 2, 3],
        [4, 5, 6]
      ];
      assert.throws(() => inverseMatrix(matrix3), Error, 'Error thrown for non-square matrix.');
    });

    QUnit.test('transposeMatrix', function (assert) {
      // Test Case 1
      const matrix1 = [
        [1, 2],
        [3, 4]
      ];
      const expectedTranspose1 = [
        [1, 3],
        [2, 4]
      ];
      assert.deepEqual(transposeMatrix(matrix1), expectedTranspose1, 'Matrix transposed correctly.');

      // Test Case 2
      const matrix2 = [
        [1, 2, 3],
        [4, 5, 6]
      ];
      const expectedTranspose2 = [
        [1, 4],
        [2, 5],
        [3, 6]
      ];
      assert.deepEqual(transposeMatrix(matrix2), expectedTranspose2, 'Matrix transposed correctly.');

      // Test Case 3: Empty matrix
      const matrix3 = [];
      const expectedTranspose3 = [];
      assert.deepEqual(transposeMatrix(matrix3), expectedTranspose3, 'Empty matrix transposed correctly.');
    });

    QUnit.test('multiply should multiply three matrices', function (assert) {
      const matrixA = [[1, 2], [3, 4]];
      const matrixB = [[5, 6], [7, 8]];
      const matrixC = [[9, 10], [11, 12]];

      const expectedResult = [[413, 454], [937, 1030]];

      const ast = new Node('multiply', [matrixA, matrixB, matrixC]);

      const result = evaluateExpression(ast, {});

      assert.deepEqual(result, expectedResult, 'Multiplication of three matrices is correct');
    });

    QUnit.test('multiply should throw an error if fewer than two matrices are provided', function (assert) {
      const matrixA = [[1, 2], [3, 4]];

      const ast = new Node('multiply', [matrixA]);

      assert.throws(function () {
        evaluateExpression(ast, {});
      }, /At least two matrices are required for the multiply operation/, 'Throws an error when fewer than two matrices are provided');
    });

  </script>
</body>

</html>